package ws.db.readtable;


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;


import ws.db.ColumnAttrPair;
import ws.db.DBOpenClose;
import ws.db.sql.*;
import ws.log.Log;


public class ReadObject <T>{


	
	Class objclass = null;
	public ReadObject(Class obj){
		objclass = obj;
	}
	
	/**
	 * 如果给出了多行的查询语句，将只读取第一行。
	 * @param:
	 * 		className - the Clas the full path is package.
	 * 		columnAttrPairs - the Column Name and Attribution Name pairs.
	 * 		m_table - the table will be access.
	 * 		m_where - the where condition.
	 * 		m_order	- the order condition.
	 * @return:
	 * 		T - the object.
	 * */
	public T getANewObject(ArrayList<ColumnAttrPair> columnAttrPairs,
							String m_table,String m_where,String m_order){
		
		DBOpenClose db = new DBOpenClose();
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		T obj = null ;
		String columns[] = new String[columnAttrPairs.size()];
		ColumnAttrPair.ChangArrayListToStringArray(columnAttrPairs, columns);
		SelectSQL sql = new SelectSQL(m_table,m_where,m_order,columns);
		try{
			db.setDirectconn(true);
			conn = db.getConn();
			stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
							ResultSet.CONCUR_READ_ONLY);
			rs = stmt.executeQuery(sql.getSQL());
			//判断是否只有一行记录
			rs.last();
			int hang = rs.getRow();
			if(hang!=1){	//如果有多行记录，则记录进日志
				Log.writeDBMiddleLayerLog("只读取一行数据，给出多行的select语句", null);
			}
			System.out.println(hang);
			rs.first();
			/*读取出所有的列类型名称*/
			ResultSetMetaData rsmd = rs.getMetaData();
			String columnClassNames[] = new String[rsmd.getColumnCount()];
			for(int dd=0; dd<columnClassNames.length;dd++){
				columnClassNames[dd] = rsmd.getColumnClassName(dd+1);
			}
			
			
			System.out.println("objclass="+objclass.toString());
			obj = readData(objclass,columnAttrPairs,
								columnClassNames,rs);
			
			
		}catch(InstantiationException instantEx){
			DoExceptionWork("反射机制，实例化对象错误:", instantEx, obj);
		}catch(InvocationTargetException invocationTargetEx){
			DoExceptionWork("InvocationTarget错误:", invocationTargetEx, obj);
		}/*catch(ClassNotFoundException notFoundEx){
			DoExceptionWork("该类无法找到:", notFoundEx, obj);
		}*/
		catch(IllegalAccessException illegalAccessEx){
			DoExceptionWork("非法访问错误:", illegalAccessEx, obj);
		}catch(NoSuchMethodException noSuchMethodEx){
			DoExceptionWork("没有对应方法:", noSuchMethodEx, obj);
		}catch(NullPointerException nullPointerex){
			DoExceptionWork("空指针错误:", nullPointerex, obj);
		}catch(SQLException sqlEx){
			DoExceptionWork("数据库错误:", sqlEx, obj);
		}finally{
			db.close(conn, stmt, rs);
		}
		return obj;
	
	}
		
	
	
	/**
	 * Do somework after Exception been throw.
	 * */
	private void DoExceptionWork(String msg,Exception ex,Object obj){
		
		System.out.print("ex.getMessage="+ex.getMessage());
		
		Log.writeDBMiddleLayerLog(msg,ex);
	
		obj = null;
	}
	
	
	/**
	 * Get the Class Object according to the columnClassName
	 * 
	 * @param:
	 * 		columnClassName - the columnClassName.
	 * @return:
	 * 		Class - the corresponding Class Object. null if the columnClassName is not support.
	 * 
	 * 
	 * */
	private Class getType(String columnClassName){
		Class type = null;
		
		if(columnClassName.equals("java.lang.Integer"))
		{
			type = int.class;
		}
		else if(columnClassName.equals("java.lang.Long"))
		{
			type = long.class;
		}
		else if(columnClassName.equals("java.lang.Float"))
		{
			type = double.class;
		}
		else if(columnClassName.equals("java.sql.Timestamp"))
		{
			type = Date.class;
		}
		else if(columnClassName.equals("java.lang.String"))
		{
			type = String.class;
		}
		else if(columnClassName.equals("java.lang.Boolean")){
			type = boolean.class;
		}
		else
		{
			Log.writeDBMiddleLayerLog("该数据类型不予支持:"+columnClassName, null);
		}
		
		return type;
	}
	
	/**
	 * Get the value from the resutset .
	 * @param:
	 * 		columnClassName - the columnClassName ,using this to decide which method the rs would use.
	 * 		rs - the ResultSet point.
	 * 		i - the column num pointing which column would be read.
	 * @return:
	 * 		Object - the value. null if the columnClassName is not support.
	 * */
	private Object getValue(String columnClassName,ResultSet rs ,int i){
		Object value = null;
		
		try{
			if(columnClassName.equals("java.lang.Integer"))
			{
				value = rs.getInt(i);
			}
			else if(columnClassName.equals("java.lang.Long"))
			{
				value = rs.getLong(i);
			}
			else if(columnClassName.equals("java.lang.Float"))
			{
				value = rs.getDouble(i);
			}
			else if(columnClassName.equals("java.sql.Timestamp"))
			{
				value = rs.getDate(i);
			}
			else if(columnClassName.equals("java.lang.String"))
			{
				value = rs.getString(i);
			}
			else if(columnClassName.equals("java.lang.Boolean")){
				value = rs.getBoolean(i);
			}
			else
			{
				Log.writeDBMiddleLayerLog("该数据类型不予支持", null);
			}
		}catch(SQLException e){
			Log.writeDBMiddleLayerLog("数据库读取错误", e);
		}
		
		return value;
	}
	
	
	/**
	 * Get Objects. 
	 * 
	 * */
	private ArrayList<T> getObjects(ArrayList<ColumnAttrPair> columnAttrPairs,
							SQLInterface sql){
		DBOpenClose db = new DBOpenClose();
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		ArrayList<T> objs = new ArrayList<T>(); 

		try{
			db.setDirectconn(true);
			conn = db.getConn();
			stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
							ResultSet.CONCUR_READ_ONLY);
			rs = stmt.executeQuery(sql.getSQL());
			
			/*读取出所有的列类型名称*/
			ResultSetMetaData rsmd = rs.getMetaData();
			String columnClassNames[] = new String[rsmd.getColumnCount()];
			for(int dd=0; dd<columnClassNames.length;dd++){
				columnClassNames[dd] = rsmd.getColumnClassName(dd+1);
			}
			
			while(rs.next()){
				T aobj = readData(objclass,columnAttrPairs,
									columnClassNames,rs);
				objs.add(aobj);
		
			}
		}catch(InstantiationException instantEx){
			DoExceptionWork("反射机制，实例化对象错误:", instantEx, objs);
		}/*catch(ClassNotFoundException classNotFoundEx){
			DoExceptionWork("Class查找不到错误:", classNotFoundEx, objs);
		}*/
		catch(InvocationTargetException invocationTargetEx){
			DoExceptionWork("InvocationTarget错误:", invocationTargetEx, objs);
		}catch(IllegalAccessException illegalAccessEx){
			DoExceptionWork("非法访问错误:", illegalAccessEx, objs);
		}catch(NoSuchMethodException noSuchMethodEx){
			DoExceptionWork("没有对应方法:", noSuchMethodEx, objs);
		}catch(NullPointerException nullPointerex){
			DoExceptionWork("空指针错误:", nullPointerex, objs);
		}catch(SQLException sqlEx){
			DoExceptionWork("数据库错误:", sqlEx, objs);
		}finally{
			db.close(conn, stmt, rs);
		}
		return objs;
	}
	
	
	/**
	 * Get serveral objects.
	 * @param:
	 * 		className - the Object you want to construct.
	 * 		columnAttrPairs - the column name and the attribution name pairs.
	 * 		m_table - the accessing table.
	 * 		m_where - the where condition.
	 * 		m_order - the order condition.
	 * @return:
	 * 		ArrayList<T> - the objects.
	 * */
	public ArrayList<T> getServeralObjects(ArrayList<ColumnAttrPair> columnAttrPairs,
											String m_table,String m_where,String m_order){
		String columns[] = new String[columnAttrPairs.size()];
		ColumnAttrPair.ChangArrayListToStringArray(columnAttrPairs, columns);
		SelectSQL sql = new SelectSQL(m_table,m_where,m_order,columns);
		return getObjects(columnAttrPairs,sql);
		
	}
	
	/**
	 * Get the top serveral objects.
	 * @param:
	 * 		className - the Object you want to construct.
	 * 		columnAttrPairs - the column name and the attribution name pairs.
	 * 		m_table - the accessing table.
	 * 		m_where - the where condition.
	 * 		m_order - the order condition.
	 * 		topnum - the top num which you want to access.
	 * @return:
	 * 		ArrayList<T> - the objects.
	 * */
	public ArrayList<T> getTopServeralObjects(ArrayList<ColumnAttrPair> columnAttrPairs,
			String m_table,String m_where,String m_order,int topnum){
		
		String columns[] = new String[columnAttrPairs.size()];
		ColumnAttrPair.ChangArrayListToStringArray(columnAttrPairs, columns);
		SelectTopRecordsSQL sql = new SelectTopRecordsSQL(m_table,
															m_where,
															m_order,
															columns,
															topnum);
		return getObjects(columnAttrPairs,sql);
		
	}

	
	
	/**
	 * Get Objects from the Start Row to the Start+count Row.
	 * @param:
	 * 		className - the Object you want to construct.
	 * 		columnAttrPairs - the column name and the attribution name pairs.
	 * 		m_table - the accessing table.
	 * 		m_where - the where condition.
	 * 		m_order - the order condition.
	 * 		startRow - the start row num.
	 * 		count - the object count you want to retrieve.
	 * @return:
	 * 		ArrayList<T> - the objects.
	 * Example:
	 * 1-10 
	 * startRow =1 
	 * count =10;
	 * */
	public ArrayList<T> getSpecilRowNumObjects(ArrayList<ColumnAttrPair> columnAttrPairs,
			String m_table,String m_where,String m_order,
			int startRow, int count){
		
		DBOpenClose db = new DBOpenClose();
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		ArrayList<T> objs = new ArrayList<T>(); 
		String columns[] = new String[columnAttrPairs.size()];
		ColumnAttrPair.ChangArrayListToStringArray(columnAttrPairs, columns);
		SelectSQL sql = new SelectSQL(m_table,m_where,m_order,columns);
	
		try{
			db.setDirectconn(true);
			conn = db.getConn();
			stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
							ResultSet.CONCUR_READ_ONLY);
			rs = stmt.executeQuery(sql.getSQL());
			/*读取出所有的列类型名称*/
			ResultSetMetaData rsmd = rs.getMetaData();
			String columnClassNames[] = new String[rsmd.getColumnCount()];
			for(int dd=0; dd<columnClassNames.length;dd++){
				columnClassNames[dd] = rsmd.getColumnClassName(dd+1);
			}
		
			rs.last();
			int totalNum =0;
			totalNum= rs.getRow();
			
			System.out.println("totalNum="+totalNum);
			
			
			if(totalNum==0){
				Log.writeDBMiddleLayerLog("数据库中不存在记录:"+sql.getSQL(), null);
			}else if(totalNum<startRow){
				rs.beforeFirst();
				while(rs.next()){
					T aobj = readData(objclass,columnAttrPairs,
										columnClassNames,rs);
					objs.add(aobj);
				}
			}else{
				rs.beforeFirst();
				rs.absolute(startRow);
				//因为totalNum >= startRow+count
				int cs=0;
				do{	
					cs++;
					T aobj = readData(objclass,columnAttrPairs,
										columnClassNames,rs);	
					objs.add(aobj);
					
				}while( cs<count && rs.next());
			}
			
		}catch(InstantiationException instantEx){
			DoExceptionWork("反射机制，实例化对象错误:", instantEx, objs);
		}/*catch(ClassNotFoundException classNotFoundEx){
			DoExceptionWork("Class查找不到错误:", classNotFoundEx, objs);
		}*/
		catch(InvocationTargetException invocationTargetEx){
			DoExceptionWork("InvocationTarget错误:", invocationTargetEx, objs);
		}catch(IllegalAccessException illegalAccessEx){
			DoExceptionWork("非法访问错误:", illegalAccessEx, objs);
		}catch(NoSuchMethodException noSuchMethodEx){
			DoExceptionWork("没有对应方法:", noSuchMethodEx, objs);
		}catch(NullPointerException nullPointerex){
			DoExceptionWork("空指针错误:", nullPointerex, objs);
		}catch(SQLException sqlEx){
			DoExceptionWork("数据库错误:", sqlEx, objs);
		}finally{
			db.close(conn, stmt, rs);
		}
		return objs;
	}

	
	private T readData(Class objclass,
						ArrayList<ColumnAttrPair> columnAttrPairs,
						String columnClassNames[],
						ResultSet rs)
					throws InstantiationException,
							NoSuchMethodException,
							IllegalAccessException,
							InvocationTargetException{
		
		T obj = null;
		obj = (T)objclass.newInstance();  //生成新的T对象
		int i=1;
		Iterator its = columnAttrPairs.iterator(); //每次都要重新生成跌代
		while(its.hasNext()){		 	
		 	Class type = null;
			Object value = null;
			type = getType(columnClassNames[i-1]);
			if(type == null)
				throw new NullPointerException("Get Type Error");
			value = getValue(columnClassNames[i-1], rs, i);
			if(value == null)
				throw new NullPointerException("Get value Error");
			Class argTypes[] ={type};  //函数参数类型
			ColumnAttrPair each = (ColumnAttrPair)its.next();
			Method m = objclass.getMethod("set"+each.attr, argTypes); //得到该函数
			Object values[] ={value}; //要调用的函数参数的值
			m.invoke(obj,values);
			i++;
		}
		return obj;
	
	}
}
